(function ($) {
  /**
   * 在元素上实现打字机输入效果
   *
   * usage
   * 1. $elem.typewriter('text', 100, function () {alert('ok')});
   * 2. $elem.typewriter(200);
   *
   * @param t {string} 显示文本 可选参数,默认为 $elem.text()
   * @param d {number} 输入时间间隔 (ms)
   * @param f {Function} 输入完成后的回调函数,可选
   */
  $.fn.typewriter = function (t, d, f) {
    if ((arguments.length < 3)  &&  $.isNumeric(t)) {
      f = d;
      d = t;
      t = null;
    }
    return  this.each(function () {
      var $this = $(this);
      var text = t || $this.html();
      var len = text.length;
      var i = 0;
      (function input() {
        if (++i > len) 
		  return  $.isFunction(f) && f();
        
		  setTimeout(function () {
          $this.html(text.slice(0, i).replace('\n', '<br/>'));
          input();
        }, d);
      })();
    });
  };

})(jQuery);



(function ($) {
  // 标记
  var running = false;

  // queue
  var toastQueue = [];

  // time
  var timeout = {
    'in': 500,
    'out': 300
  };

  function showToast(opt, cb) {
    var $toast = $('<div class="toast animate-in" />')
            .text(opt.text).addClass(opt.type).appendTo('.toast-container');

    setTimeout(function () {
      $toast.removeClass('animate-in');
      setTimeout(function () {
        $toast.addClass('animate-out');
        setTimeout(function () {
          $toast.remove();
          cb();
        }, timeout.out);
      }, opt.duration);
    }, timeout.in);
  }

  function serial() {
    var toast = toastQueue.shift();
    if (toast) {
      showToast(toast, serial);
    } else {
      running = false;
    }
  }

  /**
   * 在元素上实现打字机输入效果
   *
   * usage
   * $.toast('hehe');
   * $.toast({
   *   text: 'hehe',
   *   type: 'warning'
   * });
   *
   * @param text {string} 显示文本
   * @param duration {number} 显示时长
   * @param type {string} 类型,作为 class 附加在 toast 上
   */
  $.toast = function (text, duration, type) {
    var toast = ((arguments.length == 1)  &&  $.isPlainObject(text))  ?
        text : {
            text:        text || '',
            duration:    duration || 1000,
            type:        type || '',
        };

    toastQueue.push(toast);
    if (!running) {
        running = true;
        serial();
        toast.callback && toast.callback();
    }
  };

})(jQuery);



(function ($) {
/*
 * 黑白棋盘随机闪现效果
 * 	
 * usage:
 * @param block_all {number} the amounts of blocks;
 * @param percentage {number} the percentage of black blocks(<=1);
 * this 指向调用函数的table对象
 */
    
    /* --- choose random array --- */
    function choose_random (min, max, number) {
        var given_array = [];
        
        (function() {
			for(var i = 0; i < (max - min); i++) {
            	given_array.push( i + min );    
        	}
		})();
        
        given_array.sort(function (){
            return Math.random() > 0.5 ? -1 : 1;
        }).slice(0, number);
                         
        return given_array;
    }
    
	$.fn.chess = function (options) {
		var options = $.extend({
                block_all  : 100,
                percentage : 0.5
            }, options),
            block_all     =   options.block_all,
			block_black   =   Math.floor( block_all * options.percentage ),
            $_this        =   this,
            td_array      =   $_this.find('td'),
            random_array  =   [];
		
        /* --- 存储随机序列 --- */
		$.extend(
            random_array,
            choose_random.apply(this, [0, 99, block_black])
        );
            
		/* --- 使选中的block_black闪现 --- */
        var count = 1,
            flash_count = [];
         
        // 随机决定闪烁次数，最多10次
        (function(flash_count) {
            for(var i = 0; i < block_black; i++) {
                flash_count[i] = Math.floor( Math.random() * 10 );
            }
        })(flash_count);
        
        // 为选中的单元格绑定动画
        $(random_array).each(function (index) {
            var $_this = $(this);
            
            for(var i = 0; i < flash_count[index]; i++) {
                td_array[ random_array[index] ].style.background =
                    (i % 2)  ?  'whitesmoke'  :  'black';
            }
        });
        return this;
	}
})(jQuery);



(function(BOM) {

    function Circle(x, y, radius, color, description) {
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.color = color;
        this.description = description;

        this.currentRadius = 0;
        this.timer = null;
    }

    function Stage(el, delay) {
        this.el = el;
        this.delay = delay;
        this.stack = [];
    }

    Stage.prototype.add = function(circle) {
        this.stack.push(circle);
    }

    Stage.prototype.inCircle = function(x, y) {
        for (var i = this.stack.length - 1; i >= 0; i--) {
            var circle = this.stack[i];
            var offsetX = x - circle.x,
                offsetY = y - circle.y;
            if (circle.currentRadius * circle.currentRadius >= offsetX * offsetX + offsetY * offsetY)
                return circle;
        }
        return null;
    }

    Stage.prototype.init = function() {
        var self = this,
            ctx = self.el.getContext('2d');

        var $toast = $('<div id="canvas-toast"></div>').css({
                position:           'absolute',
                background:         'black',
                opacity:            0.7,
                padding:            4,
                'border-radius':    3,
                'font-size':        '1em',
                color:              '#ddd',
                display:            'none',
                'z-index':          100000000
            })
            .mouseenter(function() {
                $(this).css('display', 'block')
            });

        $('#canvas-wrapper').css('position', 'relative').append($toast);

        var currentCircle;

        $(this.el).mouseleave(function(e) {
            $toast.css('display', 'none');
        });
        $(this.el).mousemove(function(e) {
            var x = e.offsetX,
                y = e.offsetY,
                data = ctx.getImageData(x, y, 1, 1).data;

            if (data[0] === 204) {
                $toast.css('display', 'none');
                currentCircle = null;
            } else {
                var circle = self.inCircle(x, y);
                if (circle) {
                    if (circle == currentCircle) return;
                    else {
                        currentCircle = circle;
                        $toast
                            .css('display', 'none')
                            .fadeIn(400)
                            .html(circle.description)
                            .css({
                                display:    'block',
                                left:       circle.x,
                                top:        circle.y - 20
                            });
                    }
                }
            }
        });
    }

    Stage.prototype.play = function() {
        var ctx = this.el.getContext('2d'),
            width = this.el.width,
            height = this.el.height,
            stack = this.stack,
            delay = this.delay,
            self = this,
            circle,
            i;

        //paint the background    
        ctx.fillStyle = '#ccc';
        ctx.fillRect(0, 0, width, height);

        stack[0].timer = 0;
        var ci = 1;
        var handle = setInterval(function() {
            if (ci >= stack.length) {
                clearInterval(handle);
                self.init();
            } else {
                stack[ci].timer = 0;
                ci++;
            }
        }, delay / 5);

        //paint the circle
        var last = 0;
        var animate = function(t) {
            for (i = 0; i < stack.length; i++) {
                circle = stack[i];
                var timer = circle.timer;
                if (typeof timer === 'number' && timer < delay) {
                    var r = circle.radius;
                    var d = delay;
                    circle.currentRadius = - (r / (d * d)) * (timer * timer) + 2 * r / d * timer;
                    if (t) {
                        circle.timer += (t - last);
                    }

                    ctx.shadowColor = 'rgba(0, 0, 0, 0.05)';
                    ctx.shadowBlur = 10;
                    ctx.shadowOffsetX = 3;
                    ctx.shadowOffsetY = 3;
                    ctx.fillStyle = circle.color;

                    ctx.beginPath();
                    ctx.arc(circle.x, circle.y, circle.currentRadius, Math.PI * 2, false);
                    ctx.fill();
                }
            }

            last = t || 0;
            var handle = requestAnimationFrame(animate);
        }
        animate();
    }

    BOM.play = function (config, id, _callback) {
        var canvas = document.getElementById(id),
            scale = canvas.width;
        canvas.height = canvas.width;

        var stage = new Stage(canvas, config.delay);
        for (var i = 0; i < config.circles.length; i++) {
            var c = config.circles[i];
            stage.add(new Circle(c.x * scale, c.y * scale, c.radius * scale, c.color, c.description));
        }
        stage.play();

        if (typeof (_callback) === 'function')
            _callback();
    };

})(self);


/* --- fakeloader --- */
(function ($) {
    $.fn.fakeLoader = function(options) {
        //Defaults
        var options = $.extend({
            	timeToHide: 1600,
        	}, options),
			$_this = $(this);

        //Time to hide fakeLoader
        setTimeout(function(){
            $_this.fadeOut();
        }, options.timeToHide);
    };

	$(window).load(function(){
		centerLoader();
	  	$(window).resize(function(){
			centerLoader();
	  	});
    });

	//Center Spinner
	function centerLoader() {
		var winW = $(window).width(),
		    winH = $(window).height(),
		    spinnerW = $('.fl').outerWidth(),
		    spinnerH = $('.fl').outerHeight();

		$('.fl').css({
			'position':'absolute',
			'left':(winW/2)-(spinnerW/2),
			'top':(winH/2)-(spinnerH/2)
		}).show();
	}
}(jQuery));